<template>
  <div class="scroll" 
  :style="{ height: height, width: width }"
  :class="{'down':(state===0),'up':(state==1),refresh:(state===2),touch:touching}"
  @touchstart="touchStart($event)"
  @touchmove="touchMove($event)"
  @touchend="touchEnd($event)"
  @scroll="(onInfinite || infiniteLoading) ? onScroll($event) : undefined">
    <section class="inner" :style="{ transform: 'translate3d(0, ' + top + 'px, 0)' }">
      <header v-show="enableRefresh" class="pull-refresh">
        <slot name="pull-refresh">
           <span class="down-tip">下拉更新</span>
           <span class="up-tip">松开更新</span>
           <span class="refresh-tip">更新中</span>
        </slot>
      </header>
      <main class="main" :class="{'top-filling':topFilling, 'filling': filling&&!enableInfinite}">
        <slot></slot>
      </main>
      <footer v-show="enableInfinite" class="load-more" :class="{'filling':filling}">
        <slot name="load-more">
          <span>加载中……</span>
        </slot>
      </footer>
    </section>
  </div>
</template>

<script lang="ts">
  import { Component, Emit, Inject, Model, Prop, Provide, Vue, Watch } from 'vue-property-decorator'

  @Component
  export default class TcScrollView extends Vue{
    @Prop({ default: '100%' })
    width: string

    @Prop({ default: '100%' })
    height: string

    @Prop({ default: 40 })
    offset: number

    @Prop({ default: false })
    filling: boolean

    @Prop({ default: false })
    topFilling: boolean

    @Prop({ default: false })
    enableInfinite: boolean

    @Prop({ default: false })
    enableRefresh: boolean

    top = 0
    state = 0
    startY = 0
    startScroll = 0
    touching = false
    infiniteLoading = false

    touchStart(e) {
      this.startY = e.targetTouches[0].pageY
      this.startScroll = this.$el.scrollTop || 0
      this.touching = true
    }

    touchMove(e) {
      if (!this.enableRefresh || this.$el.scrollTop > 0 || !this.touching) {
        return
      }
      let diff = e.targetTouches[0].pageY - this.startY - this.startScroll
      if (diff > 0) e.preventDefault()
      this.top = Math.pow(diff, 0.8) + (this.state === 2 ? this.offset : 0)

      if (this.state === 2) { // in refreshing
        return
      }
      if (this.top >= this.offset) {
        this.state = 1
      } else {
        this.state = 0
      }
    }

    touchEnd(e) {
      if (!this.enableRefresh) return
      this.touching = false
      if (this.state === 2) { // in refreshing
        this.state = 2
        this.top = this.offset
        return
      }
      if (this.top >= this.offset) { // do refresh
        this.refresh()
      } else { // cancel refresh
        this.state = 0
        this.top = 0
      }
    }

    refresh() {
      this.state = 2
      this.top = this.offset
      this.onRefresh(this.refreshDone)
    }

    refreshDone() {
      this.state = 0
      this.top = 0
    }

    infinite() {
      this.infiniteLoading = true
      this.onInfinite(this.infiniteDone)
    }

    infiniteDone() {
      this.infiniteLoading = false
    }

    onScroll(e) {
      if (!this.enableInfinite || this.infiniteLoading) {
        return
      }
      let outerHeight = this.$el.clientHeight
      let innerHeight = this.$el.querySelector('.inner').clientHeight
      let scrollTop = this.$el.scrollTop
      let ptrHeight = this.onRefresh ? this.$el.querySelector('.pull-refresh').clientHeight : 0
      let infiniteHeight = this.$el.querySelector('.load-more').clientHeight
      let bottom = innerHeight - outerHeight - scrollTop - ptrHeight
      if (bottom < infiniteHeight) this.infinite()
    }

    onRefresh (e) {
      console.log('onRefresh')
      this.$emit('onRefresh', e)
    }

    onInfinite(e) {
      console.log('onInfinite')
      this.$emit('onInfinite', e)
    }
  }
</script>

<style lang="less">
@import (reference) "~@/less/resources.less";
.scroll{
  display: flex;
  flex-direction: column;
  overflow: scroll;
  -webkit-overflow-scrolling: touch;  

  .inner {
    transition-duration: 300ms;
  }

  .main{
    flex: 1;
  }

  .pull-refresh {
    position: relative;
    left: 0;
    top: -2rem;
    width: 100%;
    height: 2rem;
    display: flex;
    align-items: center;
    justify-content: center;
  }

  .touch .inner {
    transition-duration: 0ms;
  }

  .down .down-tip {
    display: block;
  }

  .up .up-tip {
    display: block;
  }

  .refresh .refresh-tip {
    display: block;
  }

  .down-tip,
  .refresh-tip,
  .up-tip {
    display: none;
  }

  .load-more {
    height: 3rem;
    display: flex;
    align-items: center;
    justify-content: center;
  }

  .filling{
    margin-bottom: @tc-tabbar-height + @separation;
  }

  .top-filling{
    padding-top: @tc-header-height;
  }
}
</style>

